#include "stdafx.h"
#include "BridgeSurface.h"
#include <TopoDS.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Wire.hxx>
#include <TopoDS_Shape.hxx>
#include <TopoDS_Edge.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <BRepAlgoAPI_Cut.hxx>
#include <BRepAlgoAPI_Fuse.hxx>
#include <BRepOffsetAPI_ThruSections.hxx>
#include <BRepPrimAPI_MakePrism.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>

DEFINE_CREATE_CLASS(BridgeSurface, "BridgeSurface")
BridgeSurface::BridgeSurface()
{
	InitParam();
}


BridgeSurface::~BridgeSurface()
{
}

void BridgeSurface::InitParam()
{
	AddParam("st", TYPE_REAL, "0.02");
	AddParam("h", TYPE_REAL, "10");
	AddParam("N", TYPE_INT, "21");
	AddParam("yPnt", TYPE_STRING, "87.4;	112.4;	137.4;	162.4;	187.4;	212.4;	237.4;	262.4;	287.6;	362.4;	427.4;	492.4;	567.4;	592.4;	617.4;	642.4;	667.4;	692.4;	717.4;	742.4;	767.4;");
	AddParam("zPnt", TYPE_STRING, "39.453;	40.188;	40.922;	41.656;	42.391;	43.125;	43.860;	44.594;	45.337;	47.189;	47.714;	47.189;	45.337;	44.594;	43.860;	43.126;	42.392;	41.658;	40.924;	40.189;	39.455;");
	AddParam("w", TYPE_STRING, "1200;");
}

ZMVector<MeshObjectBase::suDrawMesh> BridgeSurface::GetMeshData1(const ZMString& strMeshName)
{
	ZMReal st = GetParamValue<ZMReal>("st");
	ZMReal h = GetParamValue<ZMReal>("h")*0.01;
	int N = GetParamValue<int>("N");
	ZMVector<ZMPoint3D> vPntMiddle, vDir;
	ZMVector<ZMReal> w;
	for (int i = 0; i < N; ++i)
	{
		ZMReal y = GetParamValueFromIndex<ZMReal>("yPnt", i) ;
		ZMReal z = GetParamValueFromIndex<ZMReal>("zPnt", i);
		vPntMiddle.push_back(ZMPoint3D(0, y, z));
		vDir.push_back(ZMPoint3D(1, 0, 0));
		w.push_back(GetParamValueFromIndex<ZMReal>("w", i)*0.01);
	}

	ZMVector<ZMPoint3D> vPntData;
	ZMVector<ZMPoint3D> vNormalData;
	ZMVector<ZMPoint3D> vTangentData;
	ZMVector<ZMPoint2D> vUVData;
	ZMVector<int> vTriIndex;
	for (int i = 0; i < N; ++i)
	{
		ZMPoint3D pntMiddle=  vPntMiddle[i];

		ZMPoint3D pntLeft, pntRight;
		pntLeft = pntMiddle + w[i] * vDir[i] - st *w[i] * ZMPoint3D(0, 0, 1);
		pntRight = pntMiddle - w[i] * vDir[i] - st *w[i] * ZMPoint3D(0, 0, 1);
		int iOffset = vPntData.size();

		vPntData.push_back(pntLeft);		vUVData.push_back(ZMPoint2D(1, 0));	vNormalData.push_back(ZMPoint3D(0, 0, 1)); vTangentData.push_back(ZMPoint3D(1, 0, 0));
		vPntData.push_back(pntMiddle);		vUVData.push_back(ZMPoint2D(0, 0)); vNormalData.push_back(ZMPoint3D(0, 0, 1)); vTangentData.push_back(ZMPoint3D(1, 0, 0));
		vPntData.push_back(pntRight);		vUVData.push_back(ZMPoint2D(1, 0)); vNormalData.push_back(ZMPoint3D(0, 0, 1)); vTangentData.push_back(ZMPoint3D(1, 0, 0));

		vPntData.push_back(pntLeft + ZMPoint3D(0,0, h));			vUVData.push_back(ZMPoint2D(1, 0)); vNormalData.push_back(ZMPoint3D(0, 0, 1)); vTangentData.push_back(ZMPoint3D(1, 0, 0));
		vPntData.push_back(pntMiddle + ZMPoint3D(0, 0, h));		vUVData.push_back(ZMPoint2D(0, 0)); vNormalData.push_back(ZMPoint3D(0, 0, 1)); vTangentData.push_back(ZMPoint3D(1, 0, 0));
		vPntData.push_back(pntRight + ZMPoint3D(0, 0, h));		vUVData.push_back(ZMPoint2D(1, 0)); vNormalData.push_back(ZMPoint3D(0, 0, 1)); vTangentData.push_back(ZMPoint3D(1, 0, 0));

		vTriIndex.push_back(iOffset +0);		vTriIndex.push_back(iOffset + 1);		vTriIndex.push_back(iOffset + 3);
		vTriIndex.push_back(iOffset + 4);		vTriIndex.push_back(iOffset + 1);		vTriIndex.push_back(iOffset + 3);

		vTriIndex.push_back(iOffset + 4);		vTriIndex.push_back(iOffset + 1);		vTriIndex.push_back(iOffset + 5);
		vTriIndex.push_back(iOffset + 5);		vTriIndex.push_back(iOffset + 1);		vTriIndex.push_back(iOffset + 2);

	}
	for (int i = 0; i < N - 1; ++i)
	{
		int iPntSize = 6;
		int iOffset = iPntSize * i;
		vTriIndex.push_back(iOffset + 6);		vTriIndex.push_back(iOffset + 0);		vTriIndex.push_back(iOffset + 1);
		vTriIndex.push_back(iOffset + 6);		vTriIndex.push_back(iOffset + 7);		vTriIndex.push_back(iOffset + 1);

		vTriIndex.push_back(iOffset + 2);		vTriIndex.push_back(iOffset + 8);		vTriIndex.push_back(iOffset + 1);
		vTriIndex.push_back(iOffset + 8);		vTriIndex.push_back(iOffset + 7);		vTriIndex.push_back(iOffset + 1);


		vTriIndex.push_back(iOffset + 6 + 3);		vTriIndex.push_back(iOffset + 0 + 3);		vTriIndex.push_back(iOffset + 1 + 3);
		vTriIndex.push_back(iOffset + 6 + 3);		vTriIndex.push_back(iOffset + 7 + 3);		vTriIndex.push_back(iOffset + 1 + 3);

		vTriIndex.push_back(iOffset + 2 + 3);		vTriIndex.push_back(iOffset + 8 + 3);		vTriIndex.push_back(iOffset + 1 + 3);
		vTriIndex.push_back(iOffset + 8 + 3);		vTriIndex.push_back(iOffset + 7 + 3);		vTriIndex.push_back(iOffset + 1 + 3);


		vTriIndex.push_back(iOffset + 6);		vTriIndex.push_back(iOffset + 0);		vTriIndex.push_back(iOffset + 9);
		vTriIndex.push_back(iOffset + 0);		vTriIndex.push_back(iOffset + 3);		vTriIndex.push_back(iOffset + 9);


		vTriIndex.push_back(iOffset + 8);		vTriIndex.push_back(iOffset + 11);		vTriIndex.push_back(iOffset + 2);
		vTriIndex.push_back(iOffset + 2);		vTriIndex.push_back(iOffset + 11);		vTriIndex.push_back(iOffset + 5);
	}

	ZMVector<suDrawMesh> ret;
	ZMString strNodeName = strMeshName == "" ? GetObjName() : strMeshName;
	suDrawMesh drawMesh;
	drawMesh.m_pMeshData = SharedPointer<MeshData>(new MeshData);
	MeshData&meshData = *drawMesh.m_pMeshData;
	meshData.SetMeshName(strNodeName);
	meshData.SetPntData(vPntData);
	meshData.SetNormalData(vNormalData);
	meshData.SetTriIndex(vTriIndex);
	meshData.SetTangentData(vTangentData);
	meshData.SetUVData(vUVData);

	drawMesh.m_strMatName = m_materialName;
	drawMesh.m_strNodeName = strNodeName;

	ret.push_back(drawMesh);
	return ret;
}

TopoDS_Shape BridgeSurface::CreateShape()
{
	ZMReal st = GetParamValue<ZMReal>("st");
	ZMReal h = GetParamValue<ZMReal>("h");
	int N = GetParamValue<int>("N");
	ZMVector<ZMPoint3D> vPntMiddle, vDir;
	ZMVector<ZMReal> w;
	for (int i = 0; i < N; ++i)
	{
		ZMReal y = GetParamValueFromIndex<ZMReal>("yPnt", i) *100;
		ZMReal z = GetParamValueFromIndex<ZMReal>("zPnt", i) * 100;
		vPntMiddle.push_back(ZMPoint3D(0, y, z));
		vDir.push_back(ZMPoint3D(1, 0, 0));
		w.push_back(GetParamValueFromIndex<ZMReal>("w", i));
	}

	ZMVector<TopoDS_Wire> vWire;

	
	for (int i = 0; i < N ; ++i)
	{
		ZMVector<ZMPoint3D> vPnt;
		ZMVector<TopoDS_Edge> vEdgeAll;
		ZMPoint3D pntMiddle= vPntMiddle[i];

		ZMPoint3D pntLeft, pntRight;

		pntLeft = pntMiddle + w[i] * vDir[i] - st *w[i] * ZMPoint3D(0, 0, 1);
		pntRight = pntMiddle - w[i] * vDir[i] - st *w[i] * ZMPoint3D(0, 0, 1);

		vPnt.push_back(pntLeft);
		vPnt.push_back(pntMiddle);
		vPnt.push_back(pntRight);
		vPnt.push_back(pntRight + ZMPoint3D(0, 0, h));
		vPnt.push_back(pntMiddle + ZMPoint3D(0, 0, h));
		vPnt.push_back(pntLeft + ZMPoint3D(0, 0, h));
		vEdgeAll = (CreateEdgeFromPnt(vPnt));

		BRepBuilderAPI_MakeWire mkWire;
		for (const TopoDS_Edge& edge : vEdgeAll)
		{
			mkWire.Add(edge);
		}
		vWire.push_back(mkWire.Wire());
	}
	BRepOffsetAPI_ThruSections aTool(Standard_True);
	for (const TopoDS_Wire& vWire : vWire)
	{
		aTool.AddWire(vWire);
	}
	aTool.CheckCompatibility(Standard_False);
	TopoDS_Shape shape = aTool.Shape();
	
	return shape;
}